
;****************************************************************
;								*
;	A UTILITY PROGRAM TO FACILITATE COPYING FILES		*
;		    BETWEEN USER AREAS				*
;								*
;****************************************************************
;
	TITLE	'BUFFERED INTER-USER COPY ROUTINE FOR CP/M-86'
;
;	Copyright (C) 1981,1982,1984 by
;
;	Angus Bliss		Bill Bolton
;	P.O. Box 293,		Software Tools RCPM
;	Hamilton,		P.O. Box 357,
;	NSW, 2303,		Kenmore,
;	AUSTRALIA		QLD, 4069,
;				AUSTRALIA
;
;	This program is made available for public distribution
;	for NON-COMMERCIAL use only. All commercial rights
;	retained by the authors.
;
;	------------------------------------------------------
;
;	This program is built on the Intel small memory model
;	and uses the operating system 96 byte stack. It 
;	should be GENCMD with the following command line
;
;		GENCMD PUT DATA[M860]
;
;	------------------------------------------------------
;
;	VERSION LIST, most recent version first
;	---------------------------------------
;
;	1.8	Added code to close source file for
;		Concurrent DOS operation - Bill Bolton, 30/Oct/84
;
;	1.7	Translated to CP/M-86, buffer size fixed
;		at 32K (generally no lack of memory in
;		16 bit systems) - Bill Bolton 07/Aug/84
;
;	1.6	Fixed problem with zero length files writing
;		a file as large as buffer. Fixed problem of
;		large files being truncated to 32K in
;		some multifile transfers. Tidied up for
;		publication - Angus Bliss 29/Apr/82
;
;	1.5	Initial release version. Large file transfer
;		bug fixed and other minor internal changes
;		mode - Bill Bolton 3/Feb/82
;
;	1.4	Overwrite options added, user abort added,
;		filename show added and lots more comments
;		added - Bill Bolton 2/Feb/82
;
;	1.3	Transfer to $$$ file first then rename after
;		succesful close (like PIP) added - Bill Bolton
;		1/Feb/82
;
;	1.2	Wildcard file transfer added. - Bill Bolton
;		31/Jan/82
;
;	1.1	Converted to 8080 code for greater portability
;	        (now that the Godbout 8085/8088 card has given
;		8080 code a new lease of life) and presentation-
;		tidied up. - Bill Bolton 30/Jan/82
;
;	1.0	Original code in Xitan Z80 source. - Angus Bliss
;		Aug/82
;
VERSION	EQU	18			;VERSION NUMBER
;
CNTRLC	EQU	3			;CP/M 'PANIC' CHARACTER
ACR	EQU	0DH
ALF	EQU	0AH
;
WBOOT	EQU	0			;CP/M WARM BOOT ENTRY
BDOS	EQU	0005H			;CP/M BDOS ENTRY POINT
FCB	EQU	05CH			;CP/M FILE CONTROL BLOCK
FCB0	EQU	06CH
TBUF	EQU	080H			;CP/M COMMAND LINE BUFFER
;
CI	EQU	1			;BDOS CONSOLE IN
CO	EQU	2			;BDOS CONSOLE OUT
DIRECT	EQU	6			;BDOS DIRECT CONSOLE
B_PRINT	EQU	9			;BDOS CONSOLE MESSAGE
VERS	EQU	12			;BDOS RETURN VERSION NUMBER
B_OPEN	EQU	15			;BDOS OPEN FILE
B_CLOSE	EQU	16			;BDOS CLOSE FILE
SRCH_1ST EQU	17			;BDOS SEARCH FOR FILE
SRCH_NXT EQU	18			;BDOS SEARCH FOR NEXT (AMBIG) FILE
DELET	EQU	19			;BDOS DELETE FILE
B_READ	EQU	20			;BDOS SEQUENTIAL READ
B_WRITE	EQU	21			;BDOS SEQUENTIAL WRITE
MAKE	EQU	22			;BDOS CREATE NEW FILE
REN	EQU	23			;BDOS RENAME FILE
DMA	EQU	26			;BDOS SET NEW DMA
ATTRIB	EQU	30			;BDOS SET FILE ATTRIBUTES
USER	EQU	32			;BDOS SET/GET USER
;
BUFSIZ	EQU	255			;Disk buffer in sectors (32K)
M	EQU	Byte Ptr 0[BX]
;
	CSEG
	ORG	0
;
START:
	MOV	DX,(Offset MSG1)
	MOV	CL,B_PRINT
	CALL	BDOSE			;ANNOUNCE OURSELF
;	MOV	CL,VERS			;CHECK VERSION
;	INT	224			;USES BX REGISTER
;	MOV	AL,BL
;	CMP	AL,2
;	JNB	L_1	
;	JMP	ERROR3			;WRONG CP/M VERSION
;L_1:
	MOV	AL,Byte Ptr .TBUF	;PARAMETER COUNT
	CMP	AL,0			;NO PARAMETER
	JNZ	START_1	
	JMP	ERROR1
;
START_1:
	MOV	BX,FCB-1		;TAKE A COPY OF FCB
	MOV	DX,(Offset FCB2)-1	;_ TBUF
	MOV	CX,33			;LENGTH OF A FILENAME
LDIR1:
	INC	BX			;ADJUST POINTERS
	INC	DX
	MOV	AL,M			;GET A BYTE
	MOV	SI,DX			;PUT A BYTE
	MOV	[SI],AL
	DEC	CX			;ADJUST COUNT
	MOV	AL,CH
	OR	AL,CL			;ZERO YET
	JNZ	LDIR1			;NO	
	MOV	BX,TBUF			;YES
	MOV	CH,0
	MOV	CL,M			;GET COUNT
	INC	BX			;STEP OVER ANY SOURCE
	DEC	CL
	INC	BX			; DRIVE IDENTIFIER ON
	DEC	CL
	INC	BX			; FILE NAME
	DEC	CL
	MOV	AL,':'			;DRIVE DELIMITER
CCIR1:
	INC	BX
	CMP	AL,M			;MATCH
	JZ	GO_ON1
	DEC	CL
	JZ	NOT_FOUND1		;YES
	JMPS	CCIR1
;
GO_ON1:
	DEC	BX			;ADJUST PTR
	MOV	AL,M
	CMP	AL,'G'+1
	JNB	NOT_FOUND1
	CMP	AL,'A'
	JB	NOT_FOUND1
	AND	AL,7			;MAKE 0 TO 7
	MOV	Byte Ptr DEST_DRV,AL
	MOV	Byte Ptr FCB2,AL
NOT_FOUND1:
	MOV	BX,FCB
	MOV	CL,11			;GET LENGTH OF FILE NAME
	MOV	AL,'?'			;WILDCARD
CCIR2:
	INC	BX			;LOOP TO SEARCH FOR WILDCARD
	CMP	AL,M
	JZ	GO_ON2
	DEC	CL
	JZ	NOT_FOUND2
	JMPS	CCIR2
;
GO_ON2:
	MOV	AL,0FFH
	MOV	Byte Ptr WILD,AL	;SET MULTIFILE FLAG
NOT_FOUND2:
	MOV	BX,TBUF			;YES
	MOV	CH,0
	MOV	CL,M			;GET COUNT
	MOV	AL,'-'			;OPTION SPECIFIER
CCIR_3:
	INC	BX			;LOOP TO SEARCH FOR OPTIONS
	CMP	AL,M
	PUSH	BX
	JNZ	CCIR_4	
	CALL	OPTION
CCIR_4:
	POP	BX
	DEC	CL
	JNZ	CCIR_3
	JMPS	NOT_FOUND3
;
OPTION:
	LAHF				;FOUND THE FLAG
	XCHG	AL,AH
	PUSH	AX
OPT_1:
	INC	BX			;NOW LOOK FOR AN OPTION
	MOV	AL,M
	CMP	AL,'W'
	JZ	OVER_WRITE
	CMP	AL,'N'
	JZ	NO_QUERY
	POP	AX
	XCHG	AL,AH
	SAHF
	RET
;
OVER_WRITE:
	MOV	AL,0FFH
	MOV	Byte Ptr O_W,AL
	JMPS	OPT_1			;LOOK FOR ANOTHER ONE
;
NO_QUERY:
	MOV	AL,0FFH
	MOV	Byte Ptr N_Q,AL
	JMPS	OPT_1			;LOOK FOR ANOTHER ONE
;
NOT_FOUND3:
	MOV	BX,6DH			;FROM USER
	CALL	NSCAN			;GET NUMBER
	JNB	NF_4	
	JMP	ERROR2			;INVALID USER
NF_4:
	MOV	Byte Ptr FUSER,AL	;FROM USER
	MOV	BX,75H			;TO USER
	CALL	NSCAN
	JNB	NF_5	
	JMP	ERROR2
NF_5:
	MOV	Byte Ptr TUSER,AL	;TO USER
	MOV	DL,0FFH
	MOV	CL,USER			;GET CURRENT USER
	CALL	BDOSE
	MOV	Byte Ptr CUSER,AL	;SAVE IT
	MOV	AL,Byte Ptr FUSER	;FROM USER
	MOV	DL,AL			;PUT IN E
	MOV	CL,USER
	CALL	BDOSE			;SET THE USER
	MOV	BX,FCB
	MOV	AL,Byte Ptr WILD
	OR	AL,AL			;SINGLE FILE ONLY ?
	JZ	COPY_FCB		;YES
	MOV	DX,FCB
	MOV	CL,SRCH_1ST
	CALL	BDOSE
	CMP	AL,0FFH			;FOUND?
	JNZ	DIR_MATCH
	JMP	ERROR4			;NO
;
DIR_MATCH:
	ADD	AL,AL			;MULTIPLY BY 5
	ADD	AL,AL
	ADD	AL,AL
	ADD	AL,AL
	ADD	AL,AL
	MOV	BX,TBUF			;POINT TO DIRECTORY BUFFER
	MOV	DL,AL
	MOV	DH,0
	ADD	BX,DX			;BX <--- POINTER TO MATCHED FILE
COPY_FCB:
	PUSH	BX
	MOV	CL,12
	MOV	DX,(Offset FCB1)
	MOV	AL,Byte Ptr .FCB
	MOV	M,AL			;STUFF SRC DRIVE IDENT INTO FCB
C_FCB_1:
	MOV	AL,M			;COPY FCB TO FCB1 (READ FCB)
	MOV	SI,DX
	MOV	[SI],AL
	INC	BX
	INC	DX
	DEC	CL
	JNZ	C_FCB_1
	POP	BX
C_FCB_2:
	MOV	CL,11
	MOV	DX,(Offset FCB2)
	MOV	AL,Byte Ptr DEST_DRV
	MOV	SI,DX			;STUFF DEST DRIVE IDENT INTO FCB
	MOV	[SI],AL
	INC	BX
	INC	DX
C_FCB_3:
	MOV	AL,M			;COPY FCB TO FCB1 (WRITE FCB)
	AND	AL,7FH			;RESET ANY FILE ATTRIBUTES
	MOV	SI,DX
	MOV	[SI],AL
	LAHF
	INC	BX
	SAHF
	LAHF
	INC	DX
	SAHF
	DEC	CL
	JNZ	C_FCB_3
READ_FILE:
	MOV	BX,(Offset FCB1)
	CALL	SHOW
	MOV	DX,(Offset FCB1)	;CP/M DEFAULT
	MOV	CL,B_OPEN
	CALL	BDOSE			;OPEN OUR SOURCE
	CMP	AL,255
	JNZ	RD_FILE_1	
	JMP	ERROR4			;OPEN FAILURE
;
RD_FILE_1:
	XOR	AL,AL			;INITIALISE REGISTER
	MOV	Byte Ptr ACOUNT,AL	;SECTOR COUNT
	MOV	AL,BUFSIZ
	MOV	CH,AL			;SECTOR COUNT
;
READ:
	MOV	DX,(Offset BUFSTART)	;CH HAS SECTOR CNT
READ1:
	MOV	CL,DMA
	CALL	BDOSE			;SET DMA ADDRESS
	PUSH	DX			;SAVE DMA ADDR.
	MOV	DX,(Offset FCB1)
	MOV	CL,B_READ
	CALL	BDOSE			;READ A SECTOR
	POP	DX			;RESTORE DMA
	CMP	AL,1
	JZ	FINISH
	CMP	AL,0
	JZ	READ2	
	JMP	ERROR5			;READ ERROR
;
READ2:
	MOV	AL,DL			;BUMP POINTER
	ADD	AL,80H
	MOV	DL,AL
	MOV	AL,0
	ADC	AL,DH
	MOV	DH,AL			;BY 128 BYTES
	MOV	AL,Byte Ptr ACOUNT
	INC	AL
	MOV	Byte Ptr ACOUNT,AL	;SECTORS READ
	DEC	CH			;ADJUST COUNT
	JNZ	READ1			;NO
	CALL	WRITE			;FULL, SO EMPTY IT
	XOR	AL,AL			;RESET REGISTERS
	MOV	Byte Ptr ACOUNT,AL	;SECTOR COUNT
	MOV	AL,BUFSIZ
	MOV	CH,AL			;SECTOR COUNT
	JMPS	READ
;
FINISH:
	MOV	DX,(Offset FCB1)
	MOV	CL,B_CLOSE		;CLOSE SOURCE
	CALL	BDOSE
	MOV	AL,0FFH
	MOV	Byte Ptr EOF,AL		;FINISHED THIS FILE
	MOV	AL,BUFSIZ
	SUB	AL,CH
	MOV	CH,AL
	CALL	WRITE
	MOV	DX,(Offset FCB2)
	MOV	CL,B_CLOSE		;CLOSE DESTINATION
	CALL	BDOSE
	CMP	AL,255
	JNZ	FINI_1	
	JMP	ERROR9			;CLOSE FAILURE
;
FINI_1:
	CALL	RENAME			;RENAME $$$ TO TYP
	MOV	AL,Byte Ptr WILD
	OR	AL,AL			;MORE FILES?
	JNZ	FINI_2	
	JMP	DONE
;
FINI_2:
	MOV	BX,(Offset BUFSTART)
	MOV	Word Ptr BUFPT,BX	;RESET BUFFER POINTER
	XOR	AL,AL
	MOV	Byte Ptr OPEN,AL	;RESET FILE OPEN FLAG
	MOV	Byte Ptr EOF,AL		;WON'T BE EOF ON NEXT FILE
	MOV	BX,(Offset FCB1)	;POINT TO INTERNAL FCBS
	MOV	CL,64			;LENGTH OF 2 * FCB
	XOR	AL,AL
FCB_FILL1:
	MOV	M,AL			;RESET MEMORY
	LAHF				;ADJUST POINTER
	INC	BX
	SAHF
	DEC	CL			;DONE ?
	JNZ	FCB_FILL1		;NO	
	MOV	AL,Byte Ptr FUSER
	MOV	DL,AL			;SAVE DIRECTORY POINTER TIL LATER
	MOV	CL,USER
	CALL	BDOSE			;RESET TO SOURCE USER
	MOV	DX,TBUF			;RESET DMA
	MOV	CL,DMA
	CALL	BDOSE
	MOV	DX,FCB
	MOV	CL,SRCH_1ST		;START SEARCH FOR NEXT 
	CALL	BDOSE			; WILDCARD MATCH (TEDIOUS)
	MOV	AL,Byte Ptr F_COUNT	;NO FILES DONE SO FAR
	INC	AL			;JUST DONE ANOTHER ONE
	MOV	Byte Ptr F_COUNT,AL	;KEEP FOR NEXT TIME
	MOV	Byte Ptr D_COUNT,AL	;INITIALISE LOOP COUNTER
SEARCH_LOOP:
	MOV	DX,0
	MOV	CL,SRCH_NXT		;SEARCH FOR NEXT WILDCARD MATCH
	CALL	BDOSE
	MOV	Byte Ptr DIR_POINT,AL
	CMP	AL,0FFH			;NO MORE MATCH ?
	JNZ	SRC_LP_1	
	JMP	DONE			;YES

SRC_LP_1:
	MOV	AL,Byte Ptr D_COUNT	;NO, GET LOOP COUNT
	DEC	AL			;ONE SEARCH DONE
	MOV	Byte Ptr D_COUNT,AL
	JNZ	SEARCH_LOOP		;SEARCH AGAIN
	MOV	CL,DIRECT
	MOV	DL,0FFH
	CALL	BDOSE
	CMP	AL,CNTRLC		;USER WANTS ABORT ?
	JNZ	SRC_LP_2	
	JMP	U_ABORT			;YES
;
SRC_LP_2:
	MOV	AL,Byte Ptr DIR_POINT	;NO, A = POINTER INTO DIR SECTOR
	JMP	DIR_MATCH		;FOUND THE ONE WE NEEDED
;
WRITE:
	MOV	AL,Byte Ptr TUSER
	MOV	DL,AL
	MOV	CL,USER
	CALL	BDOSE			;SET DESTINATION USER
	MOV	AL,Byte Ptr OPEN
	CMP	AL,0			;FILE ALREADY OPEN ?
	JZ	WRITE_M	
	JMP	WRITE2			;YES
;
WRITE_M:
	NOT	AL			;NO
	MOV	Byte Ptr OPEN,AL	;INDICATE FILE OPEN
	MOV	DX,(Offset FCB2)
	MOV	CL,B_OPEN
	CALL	BDOSE			;ATTEMPT OPEN
	CMP	AL,255
	JZ	WRITE0			;NOT PRESENT
	MOV	AL,Byte Ptr FCB2+9	;PRESENT, CHECK R/O
	AND	AL,80H			;ISOLATE BIT
	RCL	AL,1			;PUT IN CARRY
	JNB	NOT_RO			;NOT R/O
	MOV	AL,Byte Ptr O_W
	OR	AL,AL			;OVER WRITE R/O FILE ?
	JNZ	REMOVE_RO
	JMP	ERR6A			;IS R/O
;
REMOVE_RO:
	MOV	DX,(Offset FCB2)
	MOV	CL,B_CLOSE
	CALL	BDOSE			;CLOSE FILE TO CHANGE ATTRIBUTES
	MOV	BX,(Offset FCB2)+12	;FCB2 HAS GROUP 'GARBAGE' 
	XOR	AL,AL			; FROM OPEN CALL WHICH
	MOV	CL,21			; NEEDS TO BE CLEANED OUT
	CALL	FILL_BLOCK		; FOR ATTRIBUTE CALL
	MOV	BX,(Offset FCB2)
	MOV	CL,12
R_RO:
	MOV	AL,M			;RESET ATTRIBUTES IN FILE NAME
	AND	AL,7FH
	MOV	M,AL
	LAHF
	INC	BX
	SAHF
	DEC	CL
	JNZ	R_RO
	MOV	DX,(Offset FCB2)
	MOV	CL,ATTRIB
	CALL	BDOSE
	CMP	AL,0FFH			;THIS SHOULD NEVER HAPPEN
	JNZ	OPEN_RW
	JMP	ERROR11			; BUT JUST IN CASE
;
OPEN_RW:
	MOV	DX,(Offset FCB2)
	MOV	CL,B_OPEN
	CALL	BDOSE			;OPEN, we already know it exists
NOT_RO:
	MOV	AL,Byte Ptr N_Q
	OR	AL,AL			;NO FILE EXISTS QUERY?
	JNZ	WRITE0			;YES
	CALL	ERROR6			;CHECK BEFORE DELETE
	CMP	AL,'Y'
	JZ	WRITE1			;CONTINUE
	CMP	AL,'y'
	JZ	WRITE1			;CONTINUE
	JMP	ABORT			;ANSWER NOT 'Y' OR 'y'
WRITE1:
	CALL	CRLF
WRITE0:
	MOV	BX,(Offset FCB2)+9	;POINT TO SECONDARY FILENAME
	MOV	DX,(Offset F_TYPE)
	MOV	CL,3			;LENGTH OF SECONDARY FILENAME
	MOV	CH,'$'			;TEMPORARY FILE TYPE MARKER
FILL_TYPE1:
	MOV	AL,M			;GET SECONDARY FILE NAME
	MOV	SI,DX			;SAVE IT FOR LATER
	MOV	[SI],AL
	MOV	M,CH			;STUFF IN TEMP MARKERS
	INC	BX
	INC	DX
	DEC	CL
	JNZ	FILL_TYPE1
	MOV	BX,(Offset FCB2)+12	;ZERO FILL REST OF FCB
	MOV	CL,24
	XOR	AL,AL
	CALL	FILL_BLOCK
	MOV	DX,(Offset FCB2)
	MOV	CL,MAKE
	CALL	BDOSE			;CREATE DESTINATION FILE
	CMP	AL,255
	JNZ	WRITE2
	JMP	ERROR7			;DIRECTORY FULL
;
WRITE2:
	MOV	AL,Byte Ptr ACOUNT
	OR	AL,AL			;ZERO LENGTH FILE?
	JZ	ZEXIT			;YES, DONT WRITE TO DESTINATION
	MOV	CH,AL			;ACTUAL SECTOR COUNT
	PUSH	BX
	MOV	BX,(Offset BUFSTART)
	MOV	Word Ptr BUFPT,BX	;SAVE BUFFER POINTER
	POP	BX
WRITE3:
	PUSH	BX
	MOV	BX,Word Ptr BUFPT	;GET BUFFER POINTER
	XCHG	BX,DX			;DE <---- BUFFER POINTER
	POP	BX
	PUSH	DX
	MOV	AL,DL
	ADD	AL,80H
	MOV	DL,AL
	MOV	AL,0
	ADC	AL,DH			;16 BIT ADD OF 1 SECTOR
	MOV	DH,AL
	PUSH	BX
	XCHG	BX,DX
	MOV	Word Ptr BUFPT,BX	;SAVE NEW BUFFER POINTER
	POP	BX
	POP	DX
	MOV	CL,DMA
	CALL	BDOSE			;CHANGE DMA ADDRESS
	MOV	DX,(Offset FCB2)
	MOV	CL,B_WRITE
	CALL	BDOSE			;WRITE A SECTOR
	CMP	AL,0
	JZ	WRITE4	
	JMP	ERROR8			;WRITE ERROR
;
WRITE4:
	DEC	CH			;DONE YET?
	JNZ	WRITE3			;NO
ZEXIT:					;(COME IN HERE IF ZERO LENGTH FILE)
	MOV	AL,Byte Ptr EOF
	CMP	AL,0
	JZ	ZEXIT_1	
	RET				;END
;
ZEXIT_1:
	MOV	AL,Byte Ptr FUSER
	MOV	DL,AL
	MOV	CL,USER			;SET SOURCE USER
	CALL	BDOSE
	RET
;
FILL_BLOCK:
	MOV	M,AL			;GENERAL BLOCK FILLER
	LAHF				; WITH A CONSTANT
	INC	BX
	SAHF
	DEC	CL
	JNZ	FILL_BLOCK
	RET
;
;
RENAME:
	MOV	BX,(Offset FCB2)+9	;START POINT
	MOV	CL,27			;LENGTH TO FILL
	XOR	AL,AL			;ZERO A
	CALL	FILL_BLOCK
	MOV	BX,(Offset F_TYPE)	;POINT TO FILE TYPE
	MOV	DX,(Offset FCB2)+9	;SECONDARY FILE NAME
	MOV	CL,3			;LENGTH TO MOVE
REN_LOOP1:
	MOV	AL,M			;STUFF FILE TYPE BACK INTO FCB
	MOV	SI,DX
	MOV	[SI],AL
	LAHF
	INC	BX
	SAHF
	LAHF
	INC	DX
	SAHF
	DEC	CL
	JNZ	REN_LOOP1
	MOV	DX,(Offset FCB2)
	MOV	CL,DELET
	CALL	BDOSE			;KILL ORIGINAL DESTINATION FILE
	MOV	BX,(Offset FCB2)+9
	MOV	CL,27
	XOR	AL,AL
	CALL	FILL_BLOCK		;ZERO FILL WRITE FCB YET AGAIN	
	MOV	BX,(Offset FCB2)
	MOV	DX,(Offset FCB2)+16
	MOV	CL,9
REN_LOOP2:
	MOV	AL,M			;COPY WRITE FCB TO MAKE THE
	MOV	SI,DX			; SPECIAL RENAME FORMAT FCB
	MOV	[SI],AL
	LAHF
	INC	BX
	SAHF
	LAHF
	INC	DX
	SAHF
	DEC	CL
	JNZ	REN_LOOP2
	MOV	AL,'$'			;HL = POINTER TO FCB2 +9
	MOV	CL,3
REN_LOOP3:
	MOV	M,AL			;STUFF TEMP FILE MARKERS IN
	LAHF				; THE 'FROM' PART OF FCB
	INC	BX
	SAHF
	DEC	CL
	JNZ	REN_LOOP3
	MOV	BX,(Offset F_TYPE)	;DE = FCB2+9+16
	MOV	CL,3
REN_LOOP4:
	MOV	AL,M			;STUFF FILE TYPE IN THE
	MOV	SI,DX			; 'TO' PART OF FCB
	MOV	[SI],AL
	LAHF
	INC	BX
	SAHF
	LAHF
	INC	DX
	SAHF
	DEC	CL
	JNZ	REN_LOOP4
	MOV	DX,(Offset FCB2)
	MOV	CL,REN			;DO THE RENAME
	CALL	BDOSE
	CMP	AL,0FFH			;AGAIN, THIS SHOULD NEVER HAPPEN
	JZ	ERROR10			; BUT.......
	RET
;
;ERROR AND MESSAGE HANDLING
;
ERROR1:
	MOV	DX,(Offset MSG3)
	CALL	PRINT
	MOV	DX,(Offset MSG2)
	CALL	PRINT
	JMP	ABORT
;
ERROR2:
	MOV	DX,(Offset MSG4)
	CALL	PRINT
	MOV	DX,(Offset MSG2)
	CALL	PRINT
	JMP	ABORT
;
ERROR3:
	MOV	DX,(Offset MSG5)
	CALL	PRINT
	JMPS	ABORT
;
ERROR4:
	MOV	DX,(Offset MSG6)
	CALL	PRINT
	JMPS	ABORT
;
ERROR5:
	MOV	DX,(Offset MSG7)
	CALL	PRINT
	JMPS	ABORT
;
ERROR6:
	MOV	DX,(Offset MSG8)
	MOV	CL,B_PRINT
	CALL	BDOSE			;PROMPT QUESTION
	MOV	CL,CI
	CALL	BDOSE
	RET				;RETURN WITH INPUT
;
ERR6A:
	MOV	DX,(Offset MSG8A)
	CALL	PRINT
	JMPS	ABORT
;
ERROR7:
	MOV	DX,(Offset MSG9)
	CALL	PRINT
	MOV	DX,(Offset MSG10)
	CALL	PRINT
	JMPS	ABORT
;
ERROR8:
	MOV	DX,(Offset MSG11)
	CALL	PRINT
	JMPS	ABORT
;
ERROR9:
	MOV	DX,(Offset MSG12)
	CALL	PRINT
	JMPS	ABORT
;
ERROR10:
	MOV	DX,(Offset MSG16)
	CALL	PRINT
	JMPS	ABORT
;
ERROR11:
	MOV	DX,(Offset MSG17)
	CALL	PRINT
	JMPS	ABORT
;
;
;GENERAL PURPOSE SUBROUTINES
;
PRINT:
	PUSH	DX
	CALL	CRLF
	POP	DX
	MOV	CL,B_PRINT
	CALL	BDOSE			;PRINT MESSAGE
	RET
;
U_ABORT:
	MOV	DX,(Offset MSG18)
	CALL	PRINT
	JMPS	EOJ
;
ABORT:
	MOV	DX,(Offset MSG13)
	CALL	PRINT
	JMPS	EOJ
;
CRLF:
	MOV	DL,ACR
	MOV	CL,CO
	CALL	BDOSE
	MOV	DL,ALF
	MOV	CL,CO
	CALL	BDOSE
	RET
;
DONE:
	CALL	CRLF			;NORMAL EOJ MSG
	MOV	DX,(Offset MSG14)
	MOV	CL,B_PRINT
	CALL	BDOSE
;
EOJ:
	MOV	AL,Byte Ptr CUSER	;RESET USER
	MOV	DL,AL
	MOV	CL,USER
	CALL	BDOSE
	MOV	CX,0
	MOV	DX,0
	INT	224
;
SHOW:
	CALL	CRLF
	MOV	DX,(Offset MSG15)
	MOV	CL,B_PRINT
	CALL	BDOSE
	MOV	DH,9
SHOW1:					;DISPLAY FILENAME IN READ FCB
	LAHF
	INC	BX
	SAHF
	DEC	DH
	JNZ	SHOW2
	MOV	DL,'.'			;PRINT THE SEPARATOR
	MOV	CL,CO
	CALL	BDOSE
SHOW2:
	MOV	AL,M
	CMP	AL,0
	JNZ	SHOW3
	RET
;
SHOW3:
	CMP	AL,' '			;SKIP BLANKS
	JZ	SHOW1
	MOV	DL,AL
	MOV	CL,CO
	CALL	BDOSE
	JMPS	SHOW1
;
;
BDOSE:
	PUSH	CX			;BDOS ENTRY
	PUSH	DX
	PUSH	BX
	INT	224
	POP	BX
	POP	DX
	POP	CX
	RET
;
NSCAN:
	MOV	DX,0			;CLEAR WORK	
	MOV	AL,M			;GET CHAR
	CMP	AL,'9'+1		;IS IT A DIGIT
	JNB	NSCAN2			;> 9
	CMP	AL,'0'
	JB	NSCAN2			;< 0
NSCAN0:
	SUB	AL,'0'			;REMOVE ASCII BIAS
	PUSH	BX			;SAVE PTR
	XCHG	BX,DX			;GET WORK IN BX
	PUSH	BX
	POP	DX
	SHL	BX,1
	SHL	BX,1
	ADD	BX,DX
	SHL	BX,1			;BX = BX * 10
	MOV	DH,0
	MOV	DL,AL			;NEW DIGIT
	ADD	BX,DX			;ADD IT IN
	XCHG	BX,DX			;PUT WORK BACK
	POP	BX			;RESTORE PTR
	INC	BX			;AND STEP IT
	MOV	AL,M
	CMP	AL,'9'+1
	JNB	NSCAN1
	CMP	AL,'0'
	JB	NSCAN1
	JMPS	NSCAN0			;LOOP
;
NSCAN1:	MOV	AL,DL			;GET NUMBER
	CMP	AL,16			;<= 15
	JNB	NSCAN2
	OR	AL,AL			;CLEAR CARRY
	JMPS	NSCAN3
;
NSCAN2:
	STC				;SET CARRY
NSCAN3:
	RET				;EXIT HERE
;
	DSEG
	ORG	100H
;
MSG1	DB	'PUT, CP/M-86 Version ',VERSION/10 + '0','.'
	DB	VERSION MOD 10 + '0'
	DB	', by Angus Bliss and Bill Bolton',ACR,ALF,'$'
;
MSG2	DB	'Usage:',ACR,ALF
	DB	'	A>put [d:]filename f.t [d:] [-NW] <cr>'
	DB	ACR,ALF
	DB	'Where:',ACR,ALF
	DB	'	filename - is any valid CP/M file '
	DB	'specifier',ACR,ALF
	DB	' 	f	 - is source user area',ACR,ALF
	DB	'	t	 - is destination user area'
	DB	ACR,ALF
	DB	'	d:	 - is optional drive specifier'
	DB	ACR,ALF
	DB	'	-	 - is an option flag',ACR,ALF
	DB	'	N	 - is no query to overwrite '
	DB	'existing file',ACR,ALF
	DB	'	W	 - is force overwrite of R/O '
	DB	'file',ACR,ALF,ALF
	DB	'	Will prompt if destination '
	DB	'file is already present',ACR,ALF,'$'
;
MSG3	DB	'No parameters given',ACR,ALF,'$'
;
MSG4	DB	'Invalid user number(s)',ACR,ALF,'$'
;
MSG5	DB	'Sorry - you need CP/M 2.x',ACR,ALF,'$'
;
MSG6	DB	'Open fail on source file.',ACR,ALF,'$'
;
MSG7	DB	'Read failure on source file.',ACR,ALF,'$'
;
MSG8	DB	'  Destination file is present.',ACR,ALF
	DB	'	Continue (y) or Abort (n)?$'
;
MSG8A	DB	'Destination is present and R/O.$'
;
MSG9	DB	'Open failure on destination file.$'
;
MSG10	DB	'Destination directory probably full.$'
;
MSG11	DB	'Write error on destination.$'
;
MSG12	DB	'Close fail on destination.$'
;
MSG13	DB	'ABORT - returning to CP/M.',ACR,ALF,'$'
;
MSG14	DB	'**** Normal end-of-job ****',ACR,ALF,'$'
;
MSG15	DB	'	Putting file : $'
;
MSG16	DB	'Rename error on destination.$'
;
MSG17	DB	'Rename error on R/O file.$'
;
MSG18	DB	'ABORT, Control C typed at console - '
	DB	'returning to CP/M',ACR,ALF,'$'
;
CUSER	DB	0			;INITIATING USER
FUSER	DB	0			;FILE FROM USER
TUSER	DB	0			;FILE TO USER
SIZEB	DW	0			;BUFFER IN BYTES
BUFPT	DW	0			;DMA POINTER
ACOUNT	DB	0			;ACTUAL SECTOR COUNT
OPEN	DB	0			;FILE OPEN SWITCH
EOF	DB	0			;END OF SOURCE SWITCH
WILD	DB	0			;WILDCARD SWITCH
O_W	DB	0			;OVER WRITE SWITCH	
N_Q	DB	0			;NO QUERY SWITCH
DEST_DRV DB	0			;DESTINATION DRIVE
F_COUNT	DB	0			;FILES TRANSFERED COUNTER
D_COUNT	DB	0			;FILES TO SEARCH COUNTER
DIR_POINT DB	0			;TEMP STORAGE FOR SEARCH NEXT
;
F_TYPE	DB	'   '			;SECONDARY FILE TYPE
;
; FOR RENAME AFTER WRITE
;
FCB1	DB	0,0,0,0,0,0,0,0,0	;SOURCE FCB
	DB	0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0,0,0
;
FCB2	DB	0,0,0,0,0,0,0,0,0	;Destination FCB
	DB	0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0,0,0
;
BUFSTART RB	(BUFSIZ + 1) * 128	;Disk buffer
;
BUFEND	EQU	$			;Generate symbol for SID
;
	END
